/*
 *  Copyright (c) 2022 ZhuHai Jieli Technology Co.,Ltd.
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

#include "jiffies.h"
#include "cmsis_os2.h"
#include "target_config.h"
#include "list.h"

volatile unsigned long jiffies = 0;
unsigned char jiffies_unit = 10;
void usr_timeout_del(u16 t)
{
    printf("<=%s\n", __func__);
}
u16 usr_timeout_add(void *priv, void (*func)(void *priv), u32 msec, u8 priority)
{
    return 0;
}

int usr_timeout_modify(u16 id, u32 msec)
{
    printf("%s, no defined\n", __FUNCTION__);
    return 0;
}

u32 timer_get_sec(void)
{
    return jiffies_to_msecs(jiffies) / 1000;
}

u32 timer_get_ms(void)
{
    return jiffies_to_msecs(jiffies);
}

unsigned int time_lapse(unsigned int *handle, unsigned int time_out) // 2^32/1000/60/60/24 后超时
{
    unsigned int t, t2;

    if (*handle == 0) {
        *handle = (unsigned int)timer_get_ms();
        return 0;
    }

    t = (unsigned int)timer_get_ms();
    t2 = t - *handle;

    if (t2 > time_out) {
        *handle = t;
        return t2;
    }

    return 0;
}

typedef struct {
    u32 index;
    osTimerType_t type;
    osTimerId_t timer_id;
    struct list_head entry;
    void (*func)(void *priv);
    void *priv;
    u32 msec;
} sys_timer_type;

static u32 timer_index = 0;
static struct list_head head;

static osMutexId_t mutex;

static u16 timer_build(osTimerType_t type, void *priv, void (*func)(void *priv), u32 msec, u32 index)
{
    u32 ticks;
    osTimerId_t timer_id;
    sys_timer_type *sys_timer;

    osMutexAcquire(mutex, 0);

    ticks = msec / (100 / LOSCFG_BASE_CORE_TICK_PER_SECOND);
    if (!ticks) {
        printf("timer build err, ticks ==0\n");
        osMutexRelease(mutex);
        return 0;
    }

    timer_id = osTimerNew(func, type, priv, NULL);
    if (timer_id) {
        if (osTimerStart(timer_id, ticks) == osOK) {
            sys_timer = malloc(sizeof(sys_timer_type));
            sys_timer->index    = index ? index : (++timer_index);
            sys_timer->type     = type;
            sys_timer->timer_id = timer_id;
            sys_timer->func     = func;
            sys_timer->priv     = priv;
            sys_timer->msec     = msec;
            list_add(&sys_timer->entry, &head);
            osMutexRelease(mutex);
            return sys_timer->index;
        }
    }

    printf("timer build err\n");
    osMutexRelease(mutex);
    return 0;
}

static void timer_delete(u16 t)
{
    sys_timer_type *sys_timer;

    osMutexAcquire(mutex, 0);

    list_for_each_entry(sys_timer, &head, entry) {
        if (sys_timer->index == t) {
            osTimerDelete(sys_timer->timer_id);
            list_del(&sys_timer->entry);
            free(sys_timer);
            break;
        }
    }

    osMutexRelease(mutex);
}

u16 sys_timer_add(void *priv, void (*func)(void *priv), u32 msec)
{
    return timer_build(osTimerPeriodic, priv, func, msec, 0);
}

// 未完成版 timer_to_task
u16 sys_timer_add_to_task(const char *task_name, void *priv, void (*func)(void *priv), u32 msec)
{
    return sys_timer_add(priv, func, msec);
}

void sys_timer_del(u16 t)
{
    return timer_delete(t);
}

u16 sys_timeout_add(void *priv, void (*func)(void *priv), u32 msec)
{
    return timer_build(osTimerOnce, priv, func, msec, 0);
}

void sys_timeout_del(u16 t)
{
    return timer_delete(t);
}

void sys_timer_re_run(u16 id)
{
    u8 flag = 0;
    sys_timer_type *old_timer;
    sys_timer_type new_timer;

    osMutexAcquire(mutex, 0);
    list_for_each_entry(old_timer, &head, entry) {
        if (old_timer->index == id) {
            flag = 1;
            memcpy_s(&new_timer, sizeof(sys_timer_type), old_timer, sizeof(sys_timer_type));
            break;
        }
    }
    osMutexRelease(mutex);

    if (flag) {
        timer_delete(id);
        timer_build(new_timer.type, new_timer.priv, new_timer.func, new_timer.msec, id);
    }
}

int sys_timer_modify(u16 id, u32 msec)
{
    u8 flag = 0;
    sys_timer_type *old_timer;
    sys_timer_type new_timer;

    osMutexAcquire(mutex, 0);
    list_for_each_entry(old_timer, &head, entry) {
        if (old_timer->index == id) {
            flag = 1;
            memcpy_s(&new_timer, sizeof(sys_timer_type), old_timer, sizeof(sys_timer_type));
            break;
        }
    }
    osMutexRelease(mutex);

    if (flag) {
        timer_delete(id);
        return timer_build(new_timer.type, new_timer.priv, new_timer.func, msec, id);
    }
    return 0;
}

void sys_timer_set_user_data(u16 id, void *priv)
{
    u8 flag = 0;
    sys_timer_type *old_timer;
    sys_timer_type new_timer;

    osMutexAcquire(mutex, 0);
    list_for_each_entry(old_timer, &head, entry) {
        if (old_timer->index == id) {
            flag = 1;
            memcpy_s(&new_timer, sizeof(sys_timer_type), old_timer, sizeof(sys_timer_type));
            break;
        }
    }
    osMutexRelease(mutex);

    if (flag) {
        timer_delete(id);
        timer_build(new_timer.type, priv, new_timer.func, new_timer.msec, id);
    }
}

void *sys_timer_get_user_data(u16 id)
{
    sys_timer_type *sys_timer;

    osMutexAcquire(mutex, 0);
    list_for_each_entry(sys_timer, &head, entry) {
        if (sys_timer->index == id) {
            osMutexRelease(mutex);
            return sys_timer->priv;
        }
    }
    osMutexRelease(mutex);
    return NULL;
}

void usr_timer_del(u16 t)
{
    printf("%s no define\n", __FUNCTION__);
}

int sys_timer_init(void)
{
    mutex = osMutexNew(NULL);
    INIT_LIST_HEAD(&head);
    return 0;
}

